#include "moveeffect.h"
#include <graphics/debugdraw.h>
#include <math/matrix44.h>
#include <entity/entity.h>
#include <graphics/irenderer.h>

MoveEffect::MoveEffect()
{

}

void MoveEffect::BuildQuad(gecko::Vertex* verts, gecko::Vector3f& pos, gecko::Colour& colour)
{
	static const float pointSize = 0.03f;

	verts[0].Position = gecko::Vector3f(pos.x - pointSize, pos.y - pointSize, pos.z); verts[0].Colour = colour.ToInt();
	verts[1].Position = gecko::Vector3f(pos.x + pointSize, pos.y - pointSize, pos.z); verts[1].Colour = colour.ToInt();
	verts[2].Position = gecko::Vector3f(pos.x + pointSize, pos.y + pointSize, pos.z); verts[2].Colour = colour.ToInt();
	verts[3].Position = gecko::Vector3f(pos.x - pointSize, pos.y + pointSize, pos.z); verts[3].Colour = colour.ToInt();
}

void MoveEffect::Initialise(float size, gecko::IEffect* effect)
{
	static gecko::Vertex verts[MAX_POINTS * 4];
	static unsigned short indices[MAX_POINTS * 6];

	int points = 0;
	for (int i = 0; i < MAX_POINTS * 4; i += 4)
	{
		gecko::Vector3f p(gecko::Rand2<float>() * size, gecko::Rand2<float>() * size, gecko::Rand<float>() * (-size));

		m_positions[points] = p;
		m_renderPositions[points] = p;
		points++;
	}

	int index = 0;
	for (int i = 0; i < MAX_POINTS * 4; i += 4)
	{
		indices[index++] = (unsigned short)i;
		indices[index++] = (unsigned short)i + 1;
		indices[index++] = (unsigned short)i + 2;
		indices[index++] = (unsigned short)i + 2;
		indices[index++] = (unsigned short)i + 3;
		indices[index++] = (unsigned short)i;
	}

	gecko::Geometry* mesh = new gecko::Geometry;
	mesh->Initialise(verts, MAX_POINTS * 4, indices, MAX_POINTS * 6, effect, gecko::IVertexBuffer::PT_TRIANGLELIST);

	m_geometry.m_Geometry = mesh;

	m_size = size;
}

void MoveEffect::Render(gecko::IRenderer* renderer)
{
	gecko::Matrix44 entityTransform;
	m_entity->GetTransform(entityTransform);

	gecko::Vector3f position;
	entityTransform.GetPosition(position);

	gecko::Geometry* geometry = m_geometry.m_Geometry;

	float fmodx = fmod(position.x, m_size * 2.0f);
	fmodx = fmodx < -m_size ? fmodx + (m_size * 2.0f) : fmodx;
	fmodx = fmodx > m_size ? fmodx - (m_size * 2.0f) : fmodx;

	float fmody = fmod(position.y, m_size * 2.0f);
	fmody = fmody < -m_size ? fmody + (m_size * 2.0f) : fmody;
	fmody = fmody > m_size ? fmody - (m_size * 2.0f) : fmody;

	float fmodz = fmod(position.z, m_size * 2.0f);
	fmodz = fmodz < -m_size ? fmodz + (m_size * 2.0f) : fmodz;
	fmodz = fmodz > m_size ? fmodz - (m_size * 2.0f) : fmodz;

	gecko::Vector3f fmoddedPosition = gecko::Vector3f(fmodx, fmody, fmodz);
	
	gecko::Vector3f min = (gecko::Vector3f(-m_size, -m_size, -m_size));
	gecko::Vector3f max = (gecko::Vector3f(m_size, m_size, m_size));

	for (int i = 0; i < MAX_POINTS; i++)
	{
		m_renderPositions[i] = m_positions[i] - fmoddedPosition;
		
		if ( m_renderPositions[i].x < min.x )
		{
			m_renderPositions[i].x += m_size * 2.0f;
		}

		if ( m_renderPositions[i].x > max.x )
		{
			m_renderPositions[i].x -= m_size * 2.0f;
		}

		if ( m_renderPositions[i].y < min.y )
		{
			m_renderPositions[i].y += m_size * 2.0f;
		}

		if ( m_renderPositions[i].y > max.y )
		{
			m_renderPositions[i].y -= m_size * 2.0f;
		}

		if ( m_renderPositions[i].z < min.z )
		{
			m_renderPositions[i].z += m_size * 2.0f;
		}

		if ( m_renderPositions[i].z > max.z )
		{
			m_renderPositions[i].z -= m_size * 2.0f;
		}

		m_renderPositions[i] = m_renderPositions[i] + (position);

		gecko::Vector3f posDiff = position - m_renderPositions[i];
		float alpha = posDiff.MagnitudeSq();
		alpha = gecko::Clamp<float>(0.0f, m_size * m_size, alpha);
		alpha = 1.0f - (alpha / (m_size * m_size));

		gecko::Colour colour(1.0f, 1.0f, 1.0f, alpha);
		BuildQuad(&geometry->m_vertices[i * 4], m_renderPositions[i], colour);
	}

	renderer->AddBatchedGeometry(&m_geometry);
}

void MoveEffect::Attach( gecko::Entity * entity )
{
	m_entity = entity;
}
